﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using xVal.ServerSide;

namespace MvcShop.Models
{
    public static class DataAnnotationsValidationRunner
    {
        //　TODO:　DOES　NOT　SUPPORT　METADATA　TYPE
        /////　Warning:　For　some　reason,　DataTypeAttribute.IsValid()　always　returns　"true",　regardless　of　whether
        /////　it　is　actually　valid.　Need　to　improve　this　test　runner　to　fix　that.
        //public　static　IEnumerable<ErrorInfo>　GetErrors(object　instance)
        //{
        //　　　　return　from　prop　in　TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>()
        //　　　　　　　　　　　from　attribute　in　prop.Attributes.OfType<ValidationAttribute>()
        //　　　　　　　　　　　where　!attribute.IsValid(prop.GetValue(instance))
        //　　　　　　　　　　　select　new　ErrorInfo(prop.Name,　attribute.FormatErrorMessage(string.Empty),　instance);
        //}
        ///　<summary>
        ///　Get　any　errors　associated　with　the　model　also　investigating　any　rules　dictated　by　attached　Metadata　buddy　classes.
        ///　</summary>
        ///　<param　name="instance"></param>
        ///　<returns></returns>
        public static IEnumerable<ErrorInfo> GetErrors(object instance)
        {
            var metadataAttrib = instance.GetType().GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().FirstOrDefault();
            var buddyClassOrModelClass = metadataAttrib != null ? metadataAttrib.MetadataClassType : instance.GetType();
            var buddyClassProperties = TypeDescriptor.GetProperties(buddyClassOrModelClass).Cast<PropertyDescriptor>();
            var modelClassProperties = TypeDescriptor.GetProperties(instance.GetType()).Cast<PropertyDescriptor>();
            return from buddyProp in buddyClassProperties
                   join modelProp in modelClassProperties on buddyProp.Name equals modelProp.Name
                   from attribute in buddyProp.Attributes.OfType<ValidationAttribute>()
                   where !attribute.IsValid(modelProp.GetValue(instance))
                   select new ErrorInfo(buddyProp.Name, attribute.FormatErrorMessage(string.Empty), instance);
        }
    }
}
